package utils

import (
	"fmt"
	"math/rand"
	"net/http"
	"sort"
	"strconv"
	"strings"
	"time"
)

var httpClient *http.Client

var runes = []byte{
	'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
}
var randomIsZero chan bool

func init() {
	// rand = rand.New(rand.NewSource(time.Now().UnixNano()))
	rand.Seed(time.Now().UnixNano())
	httpClient = &http.Client{}
	randomIsZero = make(chan bool, 1024)

	go func() {
		var counter int
		for {
			if isZero, ok := <-randomIsZero; ok {
				if isZero {
					counter++
				} else {
					counter = 0
				}
				if counter > 100 {
					// graylog.InfoAPI("程序异常", map[string]interface{}{
					// 	"errInfo":  "随机数连续为零",
					// 	"fileMark": "pigcome/utils.Roll",
					// 	"count":    counter,
					// })
				}
			}
		}
	}()
}

// BuildParameterString BuildParameterString
func BuildParameterString(params map[string]string) (str string) {
	for k, v := range params {
		str += fmt.Sprintf("&%s=%s", k, v)
	}
	if len(str) > 0 {
		str = str[1:]
	}
	return
}

// BuildURL BuildURL
func BuildURL(url string, params, hashs map[string]string) (str string) {
	if strings.Contains(url, "?") {
		str = fmt.Sprintf("%s&%s#%s", url, BuildParameterString(params), BuildParameterString(hashs))
	} else {
		str = fmt.Sprintf("%s?%s#%s", url, BuildParameterString(params), BuildParameterString(hashs))
	}
	return
}

// Min Min
func Min(a, b int) (c int) {
	if a >= b {
		return b
	}
	return a
}

// Max Max
func Max(a, b int) (c int) {
	if a > b {
		return a
	}
	return b
}

// MinInt64 MinInt64
func MinInt64(a, b int64) (c int64) {
	if a >= b {
		return b
	}
	return a
}

// MaxInt64 MaxInt64
func MaxInt64(a, b int64) (c int64) {
	if a > b {
		return a
	}
	return b
}

var shortRunes = []rune{
	'0', 'W', 'G', 'R', '6',
	'P', 'H', 'A', 'Z', '8',
	'X', 'B', 'N', 'Y', '2',
	'E', 'D', 'M', '3', 'T',
	'U', 'J', 'S', '1', '9',
	'K', 'C', '4', 'F', '5',
	'V', 'L', '7', 'Q',
}

var runeMap = map[rune]rune{
	'O': '0',
}

// Checksum Checksum
func Checksum(id, salt int64) (sum int64) {
	sum = id + salt + 375698
	return
}

// ChatSign ChatSign
func ChatSign(uid, salt int64) (sign int64) {
	if uid == 0 {
		return
	}
	count := 0
	for uid > 0 {
		idx := uid % 10
		uid = uid / 10
		if count%2 == 0 {
			sign = sign*10 + ((idx*3 + 5) % 10)
		} else {
			sign = sign*10 + ((idx*7 + 2) % 10)
		}
		count++
	}
	for count < 10 {
		idx := salt % 10
		salt = salt / 10
		sign = sign*10 + idx
		count++
	}
	if sign < 1000000000 {
		sign += 1234567890
	}
	return
}

// Roll 随机（有权重，slice）
func Roll(weights []int) (idx int) {
	sum := 0
	for _, w := range weights {
		sum += w
	}
	if sum == 0 {
		// go graylog.InfoAPI("程序异常", map[string]interface{}{
		// 	"errInfo":  "随机数配置错误",
		// 	"fileMark": "pigcome/utils.Roll",
		// 	"weights":  fmt.Sprintf("%v", weights),
		// })
		return 0
	}
	dice := rand.Intn(sum)
	sum = 0
	for i := 0; i < len(weights); i++ {
		if dice >= sum && dice < sum+weights[i] {
			randomIsZero <- (dice == 0)
			return i
		}
		sum += weights[i]
	}
	// go graylog.InfoAPI("程序异常", map[string]interface{}{
	// 	"errInfo":  "随机数返回错误",
	// 	"fileMark": "pigcome/utils.Roll",
	// 	"weights":  fmt.Sprintf("%v", weights),
	// 	"dice":     dice,
	// 	"sum":      sum,
	// })
	return 0
}

// RollMap 随机（有权重，map）
func RollMap(weightsMap map[int]int) (key int) {
	var weights []int
	weightsMap2 := make(map[int]int)
	sum := 0
	for rid, weight := range weightsMap {
		sum += weight
		weightsMap2[sum] = rid
		weights = append(weights, sum)
	}
	dice := rand.Intn(sum)
	idx := sort.SearchInts(weights, dice)
	key = weightsMap2[weights[idx]]
	return
}

func RollMap3(weightsMap map[int64]int) (key int64) {
	var weights []int
	weightsMap2 := make(map[int]int64)
	sum := 0
	for rid, weight := range weightsMap {
		sum += weight
		weightsMap2[sum] = rid
		weights = append(weights, sum)
	}
	dice := rand.Intn(sum)
	idx := sort.SearchInts(weights, dice)
	key = weightsMap2[weights[idx]]
	return
}

// RollMap2 随机（有权重，map）
func RollMap2(weightsMap map[string]int) (key string) {
	var weights []int
	weightsMap2 := make(map[int]string)
	sum := 0
	for rid, weight := range weightsMap {
		sum += weight
		weightsMap2[sum] = rid
		weights = append(weights, sum)
	}
	dice := rand.Intn(sum)
	idx := sort.SearchInts(weights, dice)
	key = weightsMap2[weights[idx]]
	return
}

// RollMaps 随机出多个(重复)
func RollMaps(weightsMap map[string]int, count int) (keys []string) {
	var weights []int
	weightsMap2 := make(map[int]string)
	sum := 0
	for rid, weight := range weightsMap {
		sum += weight
		weightsMap2[sum] = rid
		weights = append(weights, sum)
	}
	for i := 0; i < count; i++ {
		idx := sort.SearchInts(weights, rand.Intn(sum))
		keys = append(keys, weightsMap2[weights[idx]])
	}
	return
}

// RollMaps2 随机出多个(重复)
func RollMaps2(weightsMap map[int]int, count int) (keys []int) {
	var weights []int
	weightsMap2 := make(map[int]int)
	sum := 0
	for rid, weight := range weightsMap {
		sum += weight
		weightsMap2[sum] = rid
		weights = append(weights, sum)
	}
	for i := 0; i < count; i++ {
		idx := sort.SearchInts(weights, rand.Intn(sum))
		keys = append(keys, weightsMap2[weights[idx]])
	}
	return
}

// RollMapsUnique 随机出多个(不重复)
func RollMapsUnique(weightsMap map[int]int, count int) (keys []int) {
	var weights []int
	weightsMap2 := make(map[int]int)
	sum := 0
	for rid, weight := range weightsMap {
		sum += weight
		weightsMap2[sum] = rid
		weights = append(weights, sum)
	}
	for i := 0; i < count; i++ {
		idx := sort.SearchInts(weights, rand.Intn(sum))
		key := weightsMap2[weights[idx]]
		keys = append(keys, key)
		weightsLength := len(weights)
		switch idx {
		case 0:
			weights = weights[1:]
		case weightsLength - 1:
			weights = weights[:weightsLength-1]
		default:
			weights = append(weights[0:idx], weights[idx+1:]...)
		}
		sum = weights[weightsLength-2]
	}
	return
}

// RandString 随机字符串
func RandString(n int) (res string) {
	length := len(runes)
	v := make([]byte, n)
	for i := 0; i < n; i++ {
		v[i] = runes[rand.Intn(length)]
	}
	res = string(v)
	return
}

// RandInt RandInt
func RandInt() (a int) {
	return rand.Int()
}

// RandIntRange RandIntRange
func RandIntRange(a, b int) (c int) {
	return a + RandInt()%Max(b-a+1, 1)
}

// RandInRange RandInRange
func RandInRange(a int64, b int64) (c int64) {
	return a + int64(RandInt())%int64(Max(int(b-a), 1))
}

// RandWithoutSelf RandWithoutSelf
func RandWithoutSelf(a int64, b int64, self int64) (c int64) {
	x := RandInRange(a, b)
	if x >= self {
		//选择后半段
		return RandInRange(self+1, b)
	}
	return RandInRange(a, self)
}

// ShuffleInt64 ShuffleInt64
func ShuffleInt64(src []int64, limit int) (dest []int64) {
	dest = make([]int64, len(src))
	perm := rand.Perm(len(src))
	for i, v := range perm {
		dest[v] = src[i]
	}
	if limit > 0 && len(dest) > limit {
		dest = dest[:limit]
	}
	return
}

// InSliceInt 判断int是否在slice
func InSliceInt(items []int, one int) (in bool) {
	for _, item := range items {
		if item == one {
			return true
		}
	}
	return
}

// InSliceInt64 判断int64是否在slice
func InSliceInt64(items []int64, one int64) (in bool) {
	for _, item := range items {
		if item == one {
			return true
		}
	}
	return
}

// InSliceString 判断string是否在slice
func InSliceString(items []string, one string) (in bool) {
	for _, item := range items {
		if item == one {
			return true
		}
	}
	return
}

// GenGotLevel GenGotLevel
func GenGotLevel(gotLevel, length int) (levels []bool) {
	binary := 1
	for i := 1; i <= length; i++ {
		binary *= 2
		levels = append(levels, gotLevel&binary > 0)
	}
	return
}

func IsSameDay(timeA, timeB time.Time) bool {
	if timeA.Year() == timeB.Year() && timeA.YearDay() == timeB.YearDay() {
		return true
	}
	return false
}

/*
 * 比较版本号。
 * ret int: -1 version1 < version2
  		     0 version1 == version2
			 1 version1 > version2
*/
func CompareVersion(version1, version2 string) int {

	v1 := strings.Split(version1, ".")
	v2 := strings.Split(version2, ".")

	len1 := len(v1)
	len2 := len(v2)

	for i := 0; i < len1 && i < len2; i++ {
		n1, _ := strconv.Atoi(v1[i])
		n2, _ := strconv.Atoi(v2[i])
		if n1 < n2 {
			return -1
		} else if n1 > n2 {
			return 1
		}
	}

	if len1 < len2 {
		return -1
	} else if len1 > len2 {
		return 1
	}
	return 0
}
